package main

import (
	"fmt"
)

type Base struct {
	attr string
}

func (b Base) VMethod() {
	fmt.Println(b.attr)
}

func (pb *Base) PMethod() {
	fmt.Println(pb.attr)
}

//here use struct embedding to "inherit" Base like other languages
//in fact there is no real inherit in Go, struct embedding just hosit the fields and methods of the embedded type to its embedding type
//the real implementation is still composing an instance of `Base` to the instance of `VChild`, not real inheritance
//accessing `Base` fields and methods directly from instance of `VChild` equals to VChildInstance.Base.fieldsOrMethods. So the receiver assgined into the `Base` methods with value receiver is still the instance of `Base` rather than the instance of `VChild`, and the receiver assgined into the `Base` methods with pointer receiver is still the pointer to the instance of `Base` rather than the pointer to instance of `VChild`.
//So all the `Base` methods are non-virtual methods, they can't jump to call the same-named methods defined in `VChild`, because the `Base` methods can't get the instance or pointer of `VChild` as the receiver
type VChild struct {
	Base
}


//here the pointer of `Base` instance is composed to the instance of `PChild`
//accessing `Base` fields and methods directly from instance of `PChild` equals to PChildInstance.Base.fieldsOrMethods. 
type PChild struct {
	*Base
}

type VChild2 struct {
	Base
	attr string
}

type PChild2 struct {
	*Base
	attr string
}

func main() {
	b := Base{"base"}

    //use an instance of Base to intialize instance of VChild
    //because instance of Base is composed into instance of VChild through struct embedding
	vc := VChild{b}
    //can't use a string to initializ instance of VChild
    //because it needs an instance of Base rather than string
	// vc = VChild("child")  //invalid initialization

    //can't use a pointer of Base instance to initialize
    //because it needs an instance of Base rather than the pointer of Base instance
	// vc = VChild{&b}  //invalid initialization


    //use a pointer to instance of Base to intialize instance of VChild
    //because the pointer to instance of Base is composed into instance of VChild through struct embedding
	pc := PChild{&b}

    //can't use a Base instance to initialize
    //because it needs a pointer to  instance of Base rather than the Base instance
	// pc = PChild{b}   //invalid initialization

    //this equals to vc.Base.VMethod()
	vc.VMethod()    //VMethod is hoisted to VChild

    //this equals to vc.Base.PMethod()
	vc.PMethod()

    //this equals to pc.Base.VMethod()
	pc.VMethod()

    //this equals to vc.Base.PMethod()
	pc.PMethod()

    //invalid assignment even if explicit cast
    //because vc's underlying type is struct{Base}
    //base Base's underlying type is string{attr string}
    //there is no real inheritance in Go
	// var b1 Base = Base(vc)   
	// var b1 Base = vc

    //invalid assignment even if explicit cast
    //because pc's underlying type is struct{*Base}
    //base Base's underlying type is string{attr string}
    //there is no real inheritance in Go
    // var b1 Base = Base(pc)
	// var b1 Base = pc 

    //invalid assignment even if explicit cast
    //because &vc's underlying type is *VChild
    //pb's underlying type is *Base
    //and *VChild's base type is struct{Base}
    //and *Base's base type is struct{attr string}
    //they are pointer non-defined types
    //but their underlying type and base type are not the same
    //meanwhile VChild and Base are not real inheritance
    // var pb *Base = (*Base)(&vc)
    // var pb *Base = &vc

    //invalid assignment even if explicit cast
    //because &pc's underlying type is *PChild
    //pb's underlying type is *Base
    //and *PChild's base type is struct{*Base}
    //and *Base's base type is struct{attr string}
    //they are pointer non-defined types
    //but their underlying type and base type are not the same
    //meanwhile VChild and Base are not real inheritance
    // var pb *Base = (*Base)(&pc)
    // var pb *Base = &pc
}
